<?php
/**
 * Created by PhpStorm
 * User: 龍zero
 * Date: 2022-04-10
 * Time: 16:28
 */
declare(strict_types=1);

namespace App\Listener;


use App\Collector\PermissionMetaCollector;
use App\Model\LinPermission;
use App\Service\PermissionService;
use Hyperf\Coroutine\Exception\ParallelExecutionException;
use Hyperf\Coroutine\Parallel;
use Hyperf\Di\Annotation\Inject;
use Hyperf\Event\Annotation\Listener;
use Hyperf\Event\Contract\ListenerInterface;
use Hyperf\Server\Event\MainCoroutineServerStart;

/**
 * @Listener()
 * Class PermissionListener
 * @package App\Listener
 */
class PermissionHandleListener implements ListenerInterface
{
    /**
     * @Inject()
     * @var PermissionMetaCollector
     */
    private $metaCollector;

    /**
     * @Inject()
     * @var PermissionService
     */
    private $permissionService;

    public function listen(): array
    {
        return [
            MainCoroutineServerStart::class,
        ];
    }

    public function process(object $event):void
    {
        $this->addNewPermissions();
        $this->removeUnusedPermissions();
        $this->sortPermissions();
    }

    /**
     * @throws \Exception
     */
    private function addNewPermissions():void
    {
        $permissions = $this->metaCollector->getMetaMap();

        foreach ($permissions as $permission){
            if($permission['mount']){
                $this->createPermissionIfNotExist($permission['name'],$permission['module']);
            }
        }
    }

    private function removeUnusedPermissions(){
        //匹配不到的权限则 mount 更新false
        $allPermissions = $this->permissionService->getAllPermissions();
        $permissions = $this->metaCollector->getMetaMap();
        $ids = [];
        foreach ($allPermissions->toArray() as $permission){
            $id = $permission['id'];
            unset($permission['id']);
            if(!in_array($permission,$permissions)){
                $ids[] = $id;
            }
        }
         LinPermission::query()->whereIn('id',$ids)->update(['mount' => 0]);
    }

    private function createPermissionIfNotExist(string $name,string $module){
        $permission = LinPermission::where('name',$name)
            ->where('module',$module)->first();
        if(!$permission){
            LinPermission::create([
                'name' => $name,
                'module' => $module
            ]);
        }else{
            $permission->mount = 1;
            $permission->save();
        }
    }

    private function sortPermissions(){
        $permissions = $this->metaCollector->getMetaMap();
        $structPermissions = [];
        foreach ($permissions as $permission) {
            $structPermissions[$permission['module']][] = $permission['name'];
        }

        $parallel = new Parallel(20);
        foreach ($structPermissions as $module => $auths) {
            $parallel->add(function () use($module,$auths){
                $index = 0;
                foreach ($auths as $name) {
                    LinPermission::where('module',$module)
                        ->where('name',$name)
                        ->update(['index'=>$index]);
                    $index++;
                }
            });
        }
        try{
            $parallel->wait();
        } catch(ParallelExecutionException $e){
            throw $e;
            // $e->getResults() 获取协程中的返回值。
            // $e->getThrowables() 获取协程中出现的异常。
        }

    }

}